/**
 * I2C总线介绍
 * I2C总线（Inter IC BUS）是由Philips公司开发的一种通用数据总线
 * 两根通信线：SCL（Serial Clock）、SDA（Serial Data）
 * 同步、半双工，带数据应答
 * 通用的I2C总线，可以使各种设备的通信标准统一，
 * 对于厂家来说，使用成熟的方案可以缩短芯片设计周期、提高稳定性，
 * 对于应用者来说，使用通用的通信协议可以避免学习各种各样的自定义协议，降低了学习和应用的难度
 */
#include <REGX52.H>

//Serial Clock
sbit IIC_SCL = P2^1;
//Serial Data
sbit IIC_SDA = P2^0;

/**
 * 起始条件：SCL高电平期间，SDA从高电平切换到低电平
 * if 单片机频率过高, 需要插入延时, 下面方法同
 */
void I2C_Start() {
    IIC_SDA = 1;
    IIC_SCL = 1;
    IIC_SDA = 0;
    IIC_SCL = 0;
}

/**
 * 终止条件：SCL高电平期间，SDA从低电平切换到高电平
 */
void I2C_Stop() {
    IIC_SDA = 0;
    IIC_SCL = 1;
    IIC_SDA = 1;
}

/**
 * 发送1个字节：
 * SCL低电平期间，主机将数据位依次放到SDA线上（高位在前），然后拉高SCL，
 * 从机将在SCL高电平期间读取数据位，所以SCL高电平期间SDA不允许有数据变化，
 * 依次循环上述过程8次，即可发送一个字节
 */
void I2C_SendByte(unsigned char Data) {
    unsigned char i;
    for (i = 0; i < 8; i++) {
        IIC_SDA = Data & (0x80 >> i);
        // IIC_SDA = CY;    //TX-1C
        IIC_SCL = 1;
        IIC_SCL = 0;
    }
}

/**
 * 接收1个字节：
 * SCL低电平期间，从机将数据位依次放到SDA线上（高位在前），然后拉高SCL，
 * 主机将在SCL高电平期间读取数据位，所以SCL高电平期间SDA不允许有数据变化，
 * 依次循环上述过程8次，即可接收一个字节（主机在接收之前，需要释放SDA）
 * @return 接收的1个字节
 */
unsigned char I2C_ReceiveByte() {
    unsigned char Byte = 0, i;
    //主机在接收之前，需要释放SDA
    IIC_SDA = 1;
    for (i = 0; i < 8; i++) {
        IIC_SCL = 1;
        if (IIC_SDA) Byte |= (0x80 >> i);
        IIC_SCL = 0;
    }
    return Byte;
}

/**
 * 发送应答：
 * 在接收完一个字节之后，主机在下一个时钟发送一位数据，
 * @param AckBit 数据0表示应答，数据1表示非应答
 */
void I2C_SendAck(bit AckBit) {
    IIC_SDA = AckBit;
    IIC_SCL = 1;
    IIC_SCL = 0;
}

/**
 * 接收应答：
 * 在发送完一个字节之后，主机在下一个时钟接收一位数据，判断从机是否应答，
 * @return 数据0表示应答，数据1表示非应答（主机在接收之前，需要释放SDA）
 */
bit I2C_ReceiveAck() {
    bit acknowledge;
    //主机在接收之前，需要释放SDA
    IIC_SDA = 1;
    IIC_SCL = 1;
    acknowledge = IIC_SDA;
    IIC_SCL = 0;
    return acknowledge;
}
